package com.base.storage.provider;

import cn.hutool.core.util.ObjectUtil;
import com.base.core.codec.Base64Utils;
import com.base.core.lang.StringUtils;
import com.base.storage.enums.BusinessCodeEnums;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import com.base.core.exception.ServiceException;
import com.base.storage.config.CloudStorageConfig;
import com.base.storage.service.CloudStorageService;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class QcloudCloudStorageService extends CloudStorageService {


    public QcloudCloudStorageService(CloudStorageConfig cloudStorageConfig) {
        super(cloudStorageConfig);
    }

    /**
     * 初始化 oss 客户端
     *
     * @return
     */
    private COSClient init() {
        COSCredentials credentials = new BasicCOSCredentials(config.getDstAccessKey(), config.getDstSecretKey());
        // 初始化客户端配置 设置bucket所在的区域，华南：gz 华北：tj 华东：sh
        ClientConfig clientConfig = new ClientConfig(new Region(config.getEndPoint()));
        return new COSClient(credentials, clientConfig);
    }

    /**
     * 文件上传
     *
     * @param file 文件
     * @return 返回http地址
     */
    @Override
    public String upload(MultipartFile file) throws Exception {

        if (ObjectUtil.isEmpty(file)) {
            throw new ServiceException(BusinessCodeEnums.FILE_NOT_EXISTS, BusinessCodeEnums.FILE_NOT_EXISTS.getMessage());
        }

        //检查文件合法性
        if(!this.checkSize(file)){
            throw new ServiceException(BusinessCodeEnums.FILE_SIZE_LIMIT, BusinessCodeEnums.FILE_SIZE_LIMIT.getMessage());
        }

        if(!this.checkType(file)){
            throw new ServiceException(BusinessCodeEnums.FILE_TYPE_ILLEGAL, BusinessCodeEnums.FILE_TYPE_ILLEGAL.getMessage());
        }


        //文件名称
        String oldName = file.getOriginalFilename();
        //文件后缀
        String postfix = oldName.substring(oldName.lastIndexOf(".") + 1);

        //获取文件类型
        String fileType = file.getContentType();

        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }

        return upload(inputStream, fileType,getPath(config.getDstPrefix()) + "." + postfix);

    }

    /**
     * 上传文件
     * 主要兼容客户端经过base64位编码的文件
     *
     * @param base64
     * @return 返回http地址
     */
    @Override
    public String upload(String base64) {
        if (StringUtils.isEmpty(base64)) {
            throw new ServiceException(BusinessCodeEnums.FILE_NOT_EXISTS, BusinessCodeEnums.FILE_NOT_EXISTS.getMessage());
        }
        // 文件格式: "data:image/png;base64," + "图片的base64字符串"
        MultipartFile files = Base64Utils.base64ToMultipart(base64);
        //检查文件合法性
        if(!this.checkSize(files)){
            throw new ServiceException(BusinessCodeEnums.FILE_SIZE_LIMIT, BusinessCodeEnums.FILE_SIZE_LIMIT.getMessage());
        }

        if(!this.checkType(files)){
            throw new ServiceException(BusinessCodeEnums.FILE_TYPE_ILLEGAL, BusinessCodeEnums.FILE_TYPE_ILLEGAL.getMessage());
        }

        //老文件名
        String oldName = files.getOriginalFilename();
        //文件类型
        String fileType = files.getContentType();
        //文件后缀
        String postfix = oldName.substring(oldName.lastIndexOf(".") + 1);
        //新文件名
        String fileName = getPath(config.getDstPrefix()) + "." + postfix;

        InputStream inputStream = null;
        try {
            inputStream = files.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return upload(inputStream, fileType, fileName);
    }

    /**
     * 上传文件
     * 主要兼容客户端经过base64位编码的文件
     *
     * @param base64
     * @return 返回http地址
     */
    @Override
    public String upload(String base64, String filename) {
        if (StringUtils.isEmpty(base64)) {
            throw new ServiceException(BusinessCodeEnums.FILE_NOT_EXISTS, BusinessCodeEnums.FILE_NOT_EXISTS.getMessage());
        }
        // 文件格式: "data:image/png;base64," + "图片的base64字符串"
        MultipartFile files = Base64Utils.base64ToMultipart(base64);
        //检查文件合法性
        if(!this.checkSize(files)){
            throw new ServiceException(BusinessCodeEnums.FILE_SIZE_LIMIT, BusinessCodeEnums.FILE_SIZE_LIMIT.getMessage());
        }

        if(!this.checkType(files)){
            throw new ServiceException(BusinessCodeEnums.FILE_TYPE_ILLEGAL, BusinessCodeEnums.FILE_TYPE_ILLEGAL.getMessage());
        }

        //老文件名
        String oldName = files.getOriginalFilename();
        //文件类型
        String fileType = files.getContentType();
        //文件后缀
        String postfix = oldName.substring(oldName.lastIndexOf(".") + 1);
        //新文件名
        String fileName = getPath(config.getDstPrefix(),filename) + "." + postfix;

        InputStream inputStream = null;
        try {
            inputStream = files.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return upload(inputStream, fileType, fileName);
    }


    /**
     * 文件上传
     *
     * @param inputStream 字节流
     * @param fileType
     * @param path        文件路径，包含文件名
     * @return 返回http地址
     */
    @Override
    protected String upload(InputStream inputStream, String fileType, String path) {
        // 腾讯云必需要以"/"开头
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        //初始化客户端
        COSClient client = null;
        try{
            client = init();
        }catch (CosClientException e){
            throw new ServiceException(e.getMessage());
        }

        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        // 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(client, threadPool);
        // .....(提交上传下载请求, 如下文所属)
        // 创建上传Object的Metadata

        ObjectMetadata meta = new ObjectMetadata();
        //ContentType.APPLICATION_OCTET_STREAM.getMimeType()
        meta.setContentType(fileType);
        //被下载时网页的缓存行为
        meta.setCacheControl("no-cache");
        try {
            // 这里有个风险，因为available返回的是int类型，有长度限制，如果文件大，这个不适用。
            meta.setContentLength(inputStream.available());
        } catch (IOException e1) {
            throw new ServiceException("文件流错误，" + e1.getMessage());

        }
        //创建上传请求
        //上传文件
        PutObjectRequest putObjectRequest = new PutObjectRequest(config.getDstBucketName(),
                path, inputStream, meta);
        // 本地文件上传
        Upload upload = transferManager.upload(putObjectRequest);
        // 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）

        try {
            UploadResult uploadResult = upload.waitForUploadResult();

        } catch (CosServiceException e) {

            throw new ServiceException("服务异常，" + e.getErrorMessage());

        } catch (CosClientException e) {

            throw new ServiceException("客户端异常，" + e.getMessage());
        } catch (InterruptedException e) {

            throw new ServiceException("系统异常，" + e.getMessage());
        } finally {
            // 关闭 TransferManger
            transferManager.shutdownNow();
        }
        // 例如：https://paddy-1256559626.cosbj.myqcloud.com/images/demo/20180426/0034397501f917.png
        return path;
    }

    /**
     * 通过文件名下载文件
     *
     * @param fileNmae      要下载的文件名
     *                      例如：4DB049D0604047989183CB68D76E969D.jpg
     * @param localFileName 本地要创建的文件名
     */
    @Override
    public void downloadFile(String fileNmae, String localFileName) {

    }

    /**
     * @param fileUrl 需要删除的文件url
     * @return boolean 是否删除成功
     * @MethodName: deleteFile
     * @Description: 单文件删除
     * 例如：http://*.oss-cn-beijing.aliyuncs.com/4DB049D0604047989183CB68D76E969D.jpg
     */
    @Override
    public boolean deleteFile(String fileUrl) {
        //初始化客户端
        try{
            COSClient client = init();
            client.deleteObject(config.getDstBucketName(), fileUrl);
        }catch (CosClientException e){
            throw new ServiceException(e.getMessage());
        }
        return true;
    }
}
